package gptma.bo.services.request;

import gptma.bo.auth.UserRoles;
import gptma.bo.dao.request.ClientRequestDao;
import gptma.bo.dao.request.RequestEvaluationDao;
import gptma.bo.dao.request.RequestHistoryElementDao;
import gptma.bo.dao.task.ImputationDao;
import gptma.bo.model.employee.Employee;
import gptma.bo.model.request.ClientRequest;
import gptma.bo.model.request.RequestEvaluation;
import gptma.bo.model.request.RequestEvaluationElement;
import gptma.bo.model.request.RequestHistoryElement;
import gptma.bo.model.task.Assignment;
import gptma.bo.model.task.Imputation;
import gptma.bo.model.task.Task;
import gptma.bo.search.ClientRequestSearchCriteria;
import gptma.bo.services.task.TaskServices;
import gptma.bo.state.ClientRequestStateEngine;
import gptma.bo.state.ClientRequestStateEngineImpl;
import gptma.bo.util.ModelConstants;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;

@Stateless
@RolesAllowed({ UserRoles.ROLE_ADMIN, UserRoles.ROLE_CHIEF })
public class ClientRequestServicesImpl implements ClientRequestServices {

	@Inject
	private ClientRequestDao clientRequestDao;

	@Inject
	private ImputationDao imputationDao;

	@EJB
	private TaskServices taskServices;

	@Inject
	private RequestEvaluationDao requestEvaluationDao;

	@Inject
	private RequestHistoryElementDao historyDao;

	@Override
	public List<String> completeRequestReference(String partialReference) {
		return clientRequestDao.completeRequestReference(partialReference);
	}

	@Override
	public List<ClientRequest> findAll() {
		return clientRequestDao.findAll();
	}

	@Override
	public List<Employee> findAssignedEmployees(ClientRequest clientRequest) {
		List<Employee> ret = new ArrayList<Employee>();
		List<Task> tasks = clientRequestDao.findTasks(clientRequest);
		for (Task task : tasks) {
			for (Assignment assignment : task.getAssignments()) {
				ret.add(assignment.getEmployee());
			}
		}

		return ret;
	}

	@Override
	public List<ClientRequest> findByCriteria(
			ClientRequestSearchCriteria criteria) {
		return clientRequestDao.findByCriteria(criteria);
	}

	@Override
	public ClientRequest findByReference(String reference) {
		return clientRequestDao.findByReference(reference);
	}

	@Override
	public List<RequestHistoryElement> findHistory(ClientRequest clientRequest) {
		return clientRequestDao.findClientHistory(clientRequest);
	}

	@Override
	public List<ClientRequest> findNewRequests(int number) {
		return clientRequestDao.findNewRequests(number);
	}

	@Override
	public List<ClientRequest> findToBeTreated() {
		List<ClientRequest> ret = new ArrayList<ClientRequest>();

		// new since 6 months (default)
		List<ClientRequest> newRequests = clientRequestDao
				.findNewRequestsFiltered(180);
		for (ClientRequest clientRequest : newRequests) {
			String action = getNextAction(clientRequest);
			if (!action.equals(ModelConstants.ACTION_NO_ACTION)) {
				clientRequest.setNextAction(action);
				ret.add(clientRequest);
			}
		}

		return ret;
	}

	@Override
	public List<ClientRequest> findNonAttached() {
		return clientRequestDao.findNonAttached();
	}

	@Override
	public List<Task> findTasks(ClientRequest clientRequest) {
		return clientRequestDao.findTasks(clientRequest);
	}

	@Override
	public List<String> getModifiableStatus(ClientRequest clientRequest) {
		List<String> ret = new ArrayList<String>();

		switch (clientRequest.getRequestType()) {
		case RA:
			ret.add(ModelConstants.AR_SANS_OBJET);
			ret.add(ModelConstants.AR_REQUALIFIE_DE);
			break;

		default:
			break;
		}

		return ret;
	}

	private String getNextAction(ClientRequest clientRequest) {
		String lastState = getLastButOneState(clientRequest);
		ClientRequestStateEngine engine = new ClientRequestStateEngineImpl();
		return engine.getNextAction(clientRequest, lastState);
	}

	@Override
	public float[] getRequestCharge(ClientRequest clientRequest) {
		float[] ret = new float[3];

		float sold = 0;
		float charged = 0;
		float etc = 0;

		List<Task> tasks = clientRequestDao.findTasks(clientRequest);
		List<Imputation> taskImput = null;
		List<Imputation> allImputs = new ArrayList<Imputation>();

		for (Task task : tasks) {
			taskImput = imputationDao.findImputations(task);
			if (taskImput != null) {
				allImputs.addAll(taskImput);
			}

			etc += taskServices.getCurrentEtc(task);
			sold += task.getSoldCharge();
		}

		for (Imputation imputation : allImputs) {
			charged += imputation.getCharge();
		}

		ret[0] = sold;
		ret[1] = charged;
		ret[2] = etc;

		return ret;
	}

	@Override
	public float getSoldRequestCharge(ClientRequest clientRequest) {
		float ret = 0;

		RequestEvaluation eval = clientRequestDao.findEvaluation(clientRequest);
		List<RequestEvaluationElement> elems = eval.getElements();
		for (RequestEvaluationElement elem : elems) {
			ret += elem.getCharge();
		}

		return ret;
	}

	@Override
	public void storeRequestAndDependencies(ClientRequest clientRequest,
			RequestEvaluation requestEvaluation,
			Set<RequestHistoryElement> history) {
		clientRequestDao.save(clientRequest);
		requestEvaluationDao.save(requestEvaluation);
		historyDao.save(history);
	}
	
	@Override
	public void saveClientRequest(ClientRequest clientRequest) {
		clientRequestDao.save(clientRequest);
	}

	private String getLastButOneState(ClientRequest clientRequest) {
		String ret = ModelConstants.RFC_INCONNU;
		List<RequestHistoryElement> history = clientRequestDao
				.findClientHistory(clientRequest);
		Collections.sort(history);

		int size = history.size();
		switch (size) {
		case 0:
			break;

		case 1:
			ret = history.get(0).getState();
			break;

		default:
			ret = history.get(size - 2).getState();
			break;
		}

		return ret;
	}

}
